﻿namespace MEF_Test.Bricks
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Windows;

    using MEF_Test.Contracts;

    using Microsoft.Practices.Unity;

    public class BrowserNodeViewModel<TFileHandler> : DependencyObject, IBrowserNodeViewModel<TFileHandler> where TFileHandler : class, IFileHandler
    {
        #region Constants and Fields

        private readonly IBrowserDetailViewModelFactory _browserDetailViewModelFactory;

        private readonly DataTemplate _detailDataTemplate;

        private readonly TFileHandler _fileHandler;

        private IEnumerable<INodeAction> _actions;

        private ObservableCollection<INodeAction> _supportedActions;

        private IMediaHandler _mediaHandler;

        #endregion

        #region Constructors and Destructors


        /// <summary>
        /// Initializes a new instance of the <see cref="BrowserNodeViewModel&lt;TFileHandler, TMediaHandler&gt;"/> class.
        /// </summary>
        /// <param name="fileHandler">The file handler.</param>
        /// <param name="mediaHandler">The media handler.</param>
        /// <param name="template">The browser node template.</param>
        /// <param name="detailDataTemplate">The detail data template.</param>
        /// <param name="browserDetailViewModelFactory">The <see cref="IBrowserDetailViewModelFactory"/> factory.</param>
        public BrowserNodeViewModel(TFileHandler fileHandler, IMediaHandler mediaHandler, DataTemplate template, DataTemplate detailDataTemplate, IBrowserDetailViewModelFactory browserDetailViewModelFactory) 
        {
            if (fileHandler == null)
            {
                throw new ArgumentNullException("fileHandler");
            }

            if (mediaHandler == null)
            {
                throw new ArgumentNullException("mediaHandler");
            }

            if (browserDetailViewModelFactory == null)
            {
                throw new ArgumentNullException("browserDetailViewModelFactory");
            }

            this.Template = template;

            // TODO: Complete member initialization
            _fileHandler = fileHandler;
            this._browserDetailViewModelFactory = browserDetailViewModelFactory;
            this.MediaHandler = mediaHandler;
            _detailDataTemplate = detailDataTemplate;

            // TODO : optimize this !
            foreach (var item in fileHandler.GetSupportedActions(this))
            {
                if (item != null)
                {
                    SupportedActions.Add(item);
                }
            }
        }

        #endregion


        #region Properties

        //FIXME : How is this really still usefull ?? please document this better !!

        /// <summary>
        /// Gets the NodeActionBases supported by the Node.
        /// </summary>
        public IEnumerable<INodeAction> Actions
        {
            get
            {
                // we assume no one else than this getter sets _actions, so if it has been instanciated once here, it will never be again !
                // (that's why we can add an evenhandler on _exportedActions.CollectionChanged without having to check if one exists already )
                if (_actions == null)
                {
                    // retrieve the list of supported actions
                    _actions = getFilteredActions();

                    var actionsManager = IoC.Current.Resolve<IActionsManager>();

                    // if the part gets new import through a recomposition, we'll have to update the supported actions. (some new compatible actions might have become available)
                    actionsManager.ExportedActions.CollectionChanged += (o, e) => _actions = getFilteredActions();
                }
                return _actions;
            }
        }

        /// <summary>
        /// Gets the file handler.
        /// </summary>
        /// <value>The file handler.</value>
        public TFileHandler FileHandler
        {
            get { return _fileHandler; }
        }

        /// <summary>
        /// Gets all the actions supported by the current node.
        /// </summary>
        public ObservableCollection<INodeAction> SupportedActions
        {
            get
            {
                if (_supportedActions == null)
                {
                    _supportedActions = new ObservableCollection<INodeAction>();
                }
                return _supportedActions;
            }
        }

        /// <summary>
        /// Gets or sets the template.
        /// </summary>
        /// <value>The template.</value>
        public DataTemplate Template { get; private set; }

        /// <summary>
        /// Gets the media handler.
        /// </summary>
        /// <value>The media handler.</value>
        public IMediaHandler MediaHandler { get; private set; }

        /// <summary>
        /// Gets the file handler.
        /// </summary>
        /// <value>The file handler.</value>
        /// <remarks>Explicit implementation, hidden but ensures the interface is implemented with the right signature.</remarks>
        IFileHandler IBrowserNodeViewModel.FileHandler
        {
            get { return _fileHandler; }
        }        

        #endregion

        #region Implemented Interfaces

        #region IBrowserNodeViewModel

        public IBrowserDetailViewModel CreateDetailViewModel()
        {
            return _browserDetailViewModelFactory.Create(FileHandler, MediaHandler, SupportedActions, this._detailDataTemplate);
        }

        public IActionContextProvider SelectProvider(IEnumerable<IActionContextProvider> compatibleProviders, INodeAction action)
        {
            //TODO: Write a real provider selection based on a prioritized list (stored in a config file ? )
            return compatibleProviders.FirstOrDefault();
        }

        #endregion

        #endregion

        #region Methods

        private IEnumerable<INodeAction> getFilteredActions()
        {            
            var actionsManager = IoC.Current.Resolve<IActionsManager>();

            // Linq is awesome :)
            // returns only the available actions exported which are compatible with this Node.            
            var filteredActions = (from exportedAction in actionsManager.ExportedActions
                                   where SupportedActions.Contains(exportedAction.Metadata["Action"])
                                   select exportedAction.Value).ToList();

            return filteredActions;
        }

        #endregion
    }
}